with Ada.Strings.Bounded; use Ada.Strings.Bounded;

with GNAT.Regpat;

with App_Configuration; use App_Configuration;


--
-- Find Content-Length header's numeric value
--

package body Headers_Parser.Content_Length is

   --
   -- Find Content-Length header's numeric value
   --

   function Get_Length( HTTP_Data : in HTTP_String_Sub_Type ) return Natural
   is

      --
      -- obtain headers, separating from content
      --

      Headers_Found : constant String := Parse_Headers( HTTP_Data );


      --
      -- Regpat library
      --
      --    require Regpat procedural 'Pattern_Matcher' and 'Match_Array' types
      --       and 'No_Match' constant in order to locate desired substring:
      --
      --          'Content-Length: xxx..'
      --

      use GNAT.Regpat;


      --
      -- Regpat 'Match_Array' type
      --

      -- illegal:
      --
      --    Found_Pos : Match_Array ( Match_Count'First ..
      --                              Match_Count'Last );
      --
      -- must define the number of groups expected:
      --
      --    have one group in the pattern:
      --
      --       ([0-9]+)
      --

      Found_Pos : Match_Array ( 1 .. 1 );


      --
      -- Regpat 'Pattern_Matcher' type
      --

      Value_RegEx : constant Pattern_Matcher := Compile(

            Expression => Pattern_Str );


      --
      -- define temporary Bounded String for containing numeric Content-Length
      --    found in Header
      --

      package Value_Bounded_String_Type is new Ada.Strings.Bounded

            .Generic_Bounded_Length( Max_Number_Digits );


      --
      -- temporary String to contain the Match result
      --

      Value_Bounded_String : Value_Bounded_String_Type.Bounded_String;


      --
      -- temporary Natural to contain the Match result
      --
      -- note:
      --
      --    Max_Input is generic package parameter
      --

      subtype Value_Sub_Type is Natural range 0 .. Max_Input;

      Value : Value_Sub_Type := 0;


   begin

      --
      -- preconditional check of argument
      --

      if( Headers_Found'Length < 1 ) then

         Error_Message( "Empty HTTP headers, content argument." );

         return 0;

      end if;


      --
      -- purge any previous results held by bounded String instance
      --

      Value_Bounded_String_Type.Delete( Value_Bounded_String,
                                        1,
                                        Value_Bounded_String_Type.Length(

                                             Value_Bounded_String ));

      --
      -- note
      --
      --    'Self', 'Data', 'Matches' parameters vary from simpler 'Regexp'
      --       library and its inline, functional 'Match'
      --

      Match ( Self    => Value_RegEx,
              Data    => Headers_Found,
              Matches => Found_Pos );

      if( Found_Pos'Length < 1 ) then

         Error_Message( "Content length header value not found."
                        & Ascii.LF
                        & "Zero length match array." );
         return 0;

      end if;


      if( Found_Pos( Found_Pos'First ) = No_Match ) then

         Error_Message( "Content length header value not found, match array "
                        & Ascii.LF
                        & "1st element contains No_Match" );

         return 0;

      end if;


      --
      -- grab the String slice containing the Content-Length's numeric value
      --

      Value_Bounded_String_Type.Append( Value_Bounded_String,

            Headers_Found( Found_Pos( Found_Pos'First ).First  ..

                           Found_Pos( Found_Pos'First ).Last ));


      if( Value_Bounded_String_Type.Length( Value_Bounded_String ) < 1 ) then

         Error_Message("Failed to extract content-length header value");

         return 0;

      end if;


      --
      -- assign to temporary Natural with range
      --
      --    use of Natural'Value also provides a range check, but is excessive
      --

      Value := Natural'Value( Value_Bounded_String_Type.To_String(

                              Value_Bounded_String ));

      return Value;


   end Get_Length;


end Headers_Parser.Content_Length;